#include <stdio.h>
#include <GL/glew.h>

#include "font.h"
#include "common.h"
#include "widgets.h"
#include "game.h"
#include "main.h"
#include "input.h"
#include "Log.h"

#include "math.h"
#include "camera.h"
#include "map/Map.h"
#include "map/MapRenderer.h"
#include "models/Tree/TreeCreator.h"

#include "FullscreenQuad.h"
#include "FrameBufferObject.h"

#include "shaderManager.h"
#include "textureManager.h"
#include "assert.h"

namespace Tmpl {

static float zoom = 3.0f;
static float tilt = 90.0f;
static Map* map = 0;
static MapRenderer* mapRender = 0;
static Vec2f playerPos = Vec2f(0,0);
static FrameBufferObject* fbo = 0;
static ShaderProgram* fogShader = 0;

static TreeCreator* treeCreator = 0;

void Game::Init()
{
	Log::OpenConsole();
	Log::Print("GL_VERSION: %s", glGetString(GL_VERSION));

	TextureManager::Init();

	fbo = new FrameBufferObject();

	fogShader = ShaderManager::LoadShader("Data/Fog");

	treeCreator = new TreeCreator();

	/*
	// Create Map
	map = new Map();

	// Create the Zones
	MapZoneType* dirt = new MapZoneType(0.5f, 0.2f);
	dirt->AddTexture( new MapZoneTexture("Data/Dirt.png"));
	dirt->AddTexture( new MapZoneTexture("Data/Erde04.png"));
	map->AddZoneType(dirt);

	MapZoneType* grass = new MapZoneType(0.15f, 0.05f);
	grass->AddTexture( new MapZoneTexture("Data/fels06.png"));
	grass->AddTexture( new MapZoneTexture("Data/grass01.png"));
	map->AddZoneType(grass);

	MapZoneType* molten = new MapZoneType(0.5f, 0.8f, 0.5f);
	molten->AddTexture( new MapZoneTexture("Data/MoltenRock.png"));
	molten->AddTexture( new MapZoneTexture("Data/MoltenRock2.png"));
	molten->AddTexture( new MapZoneTexture("Data/Rock.png"));
	map->AddZoneType(molten);

	MapZoneType* summergrass = new MapZoneType(0.1f, 0.0f);
	summergrass->AddTexture( new MapZoneTexture("Data/SummerGrass.png"));
	summergrass->AddTexture( new MapZoneTexture("Data/Grass.png"));
	map->AddZoneType(summergrass);

	MapZoneType* sand = new MapZoneType(0.1f, 0.3f, 0.75f);
	sand->AddTexture( new MapZoneTexture("Data/sand01.png"));
	sand->AddTexture( new MapZoneTexture("Data/sand02.png"));
	map->AddZoneType(sand);
	*/

	/*
	map->AddTexture("Data/road.png");
	map->AddTexture("Data/solidstones.png");
	map->AddTexture("Data/stoneroad.png");
	*/

	// Generate the map
	//map->GenerateMap(12912912, 16, 256);

	// Create Map Renderer
	//mapRender = new MapRenderer(map, 128);

	Camera::SetRot(Vec3f(0.0f, 0.0f, 0.0f));
	//Camera::SetPos(Vec3f(50.0f, 5.0f, 50.0f));
	Camera::SetPos(Vec3f(0.0f, 5.0f, 10.0f));

	glClearColor(0.0f,0.0f,0.0f,1);

	WinProperties window = WinGetProperties();
	Resize(window.w, window.h);
}

void Game::Resize(int w, int h)
{
	if (fbo)
	{
		Log::Print("Resizing: %d x %d", w, h);
		fbo->Init(w, h, 1, GL_RGBA8);

		treeCreator->SetSize(200, h-10);
		treeCreator->SetPos(w-205, 5);
	}
}
static bool snap = true;
void Game::Tick(float deltaTime)
{
	GLenum err = glGetError();
	if (err != GL_NO_ERROR)
	{
		Log::Print("Opengl ERROR! (%s)", gluErrorString(err));
	}

	TextureManager::Update(deltaTime);

	// Update World
	Camera::Tick(deltaTime * 2.0f);
	//float height = map->GetHeightAtPos(Vec2f(Camera::GetPos().x, Camera::GetPos().z));
	//if (snap) Camera::SetPos(Vec3f(Camera::GetPos().x, height+0.15f, Camera::GetPos().z));
	//mapRender->Update(Camera::GetPos(), Camera::GetFacing());

	//if (key.IsPressed(TK_SPACE)) snap = !snap;

	// Render Terrain to FBO
	fbo->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	WinProperties window = WinGetProperties();
	Matrix4x4f proj;
	proj.SetPerspective(80.0f, float(window.w) / float(window.h), 0.01f, 256.0f);
	//Matrix4x4f mat = Camera::GetRotMatrix();
	Matrix4x4f mat = Camera::GetMatrix();
	if (key.IsDown(TK_SPACE)) glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
	treeCreator->GetTree()->Render(proj, &mat, 1);
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	//mapRender->Render(proj, mat);
	fbo->Unbind();

	// Render Terrain FBO with Fog
	glDisable(GL_DEPTH_TEST);
	fbo->BindAllTextures();
	fogShader->Use();
	fogShader->Uniform1i("Tex", 0);
	fogShader->Uniform1i("Depth", 1);
	fogShader->Uniform1f("Near", 1.0f);
	fogShader->Uniform1f("Far", 256.0f);
	FullScreenQuad::Draw(fogShader);
	fogShader->UnUse();
	fbo->UnbindAllTextures();
	glEnable(GL_TEXTURE_2D);

	// Update Treecreator
	treeCreator->Tick(deltaTime);
	treeCreator->Draw();

	// Render GUI info
	char buffer[256];

	Vec3f camPos = Camera::GetPos(); Vec3f camRot = Camera::GetRot();
	TmplFont.Print("Camera: ", 2, 2, 0xFFFFFFFF, Font::LEFT, Font::TOP);
	sprintf_s(buffer, "pos %2.1f %2.1f %2.1f rot %2.1f %2.1f %2.1f", camPos.x, camPos.y, camPos.z, camRot.x, camRot.y, camRot.z );
	TmplFont.Print(buffer, 102, 2, 0xFFFFFFFF, Font::LEFT, Font::TOP);

	TmplFont.Print("Triangles: ", 2, 12, 0xFFFFFFFF, Font::LEFT, Font::TOP);
	sprintf_s(buffer, "%d", treeCreator->GetTree()->GetTriangleCount());
	TmplFont.Print(buffer, 102, 12, 0xFFFFFFFF, Font::LEFT, Font::TOP);




	/*
	// Render GUI info
	char buffer[256];
	TmplFont.Print("Triangles: ", 2, 2, 0xFFFFFFFF, Font::LEFT, Font::TOP);
	sprintf_s(buffer, "%d", mapRender->GetTriangleCount());
	TmplFont.Print(buffer, 102, 2, 0xFFFFFFFF, Font::LEFT, Font::TOP);

	TmplFont.Print("Textures: ", 2, 12, 0xFFFFFFFF, Font::LEFT, Font::TOP);
	sprintf_s(buffer, "%d", mapRender->GetTextureCount());
	TmplFont.Print(buffer, 102, 12, 0xFFFFFFFF, Font::LEFT, Font::TOP);
	*/
}

void Game::Shutdown()
{
	FullScreenQuad::Destroy();
	TextureManager::Exit();
}

}; // namespace Tmpl
